package htj.myspring;


import htj.myspring.annotation.Autowired;
import htj.myspring.annotation.Component;
import htj.myspring.annotation.Qualifier;
import htj.myspring.annotation.Value;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

public class MyAnnotationConfigApplicationContext {
    Map<String,Object> ioc = new HashMap<String, Object>();
    public MyAnnotationConfigApplicationContext(String basePackages) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
        //拿到原材料BeanDefinition 1.beanName2.beanClass
        Set<BeanDefinition> beanDefinitions =  findBeanDefinition(basePackages);
        //根据原材料创建对象放到ioc容器
        createObject(beanDefinitions);
        //自动装载
        autowireObject(beanDefinitions);
    }
    public void autowireObject(Set<BeanDefinition> beanDefinitions){
        Iterator<BeanDefinition> iterator = beanDefinitions.iterator();
        while (iterator.hasNext()) {
            BeanDefinition beanDefinition = iterator.next();
            Class clazz = beanDefinition.getBeanClass();
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                Autowired annotation = declaredField.getAnnotation(Autowired.class);
                if(annotation!=null){
                    Qualifier qualifier = declaredField.getAnnotation(Qualifier.class);
                    if(qualifier!=null){
                        //byName
                        try {
                            String beanName = qualifier.value();
                            Object bean = getBean(beanName);
                            String fieldName = declaredField.getName();
                            String methodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
                            Method method = clazz.getMethod(methodName, declaredField.getType());
                            Object object = getBean(beanDefinition.getBeanName());
                            method.invoke(object, bean);
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }else{
                        //byType
                    }
                }
            }
        }
    }
    public Object getBean(String beanName){
        return ioc.get(beanName);
    }
    public void createObject(Set<BeanDefinition> beanDefinitions) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Iterator<BeanDefinition> iterator = beanDefinitions.iterator();
        while(iterator.hasNext()){
            BeanDefinition beanDefinition = iterator.next();
            Field[] fields = beanDefinition.getBeanClass().getDeclaredFields();
            Object instance = beanDefinition.getBeanClass().newInstance();
            for(Field field:fields){
                Value annotation = field.getAnnotation(Value.class);
                if(annotation != null){
                    String value = annotation.value();
                    String name = field.getName();
                    name = "set" + name.substring(0,1).toUpperCase()+name.substring(1);
                    Object val = null;
                    switch (field.getType().getName()){
                        case "java.lang.Integer":
                            val = Integer.parseInt(value);
                            break;
                        case "java.lang.String":
                            val = value;
                            break;
                    }
                    beanDefinition.getBeanClass().getMethod(name,field.getType()).invoke(instance,val);
                }
            }
            ioc.put(beanDefinition.getBeanName(),instance);
        }
    }

    public Set<BeanDefinition> findBeanDefinition(String basePackages) {
        Set<Class<?>> classes = MyTools.getClasses(basePackages);
        Iterator<Class<?>> iterator = classes.iterator();
        Set<BeanDefinition> set = new HashSet<BeanDefinition>();
        while(iterator.hasNext()){
            Class<?> aClass = iterator.next();
            Component component = aClass.getAnnotation(Component.class);
            if(component != null){
                String beanName;
                if(!"".equals(component.value())){
                    beanName = component.value();
                }else{
                    beanName = aClass.getName();
                    beanName = beanName.replaceAll(aClass.getPackage().getName()+".","");
                    beanName = beanName.substring(0,1).toLowerCase()+beanName.substring(1);
                }
                set.add(new BeanDefinition(beanName,aClass));
            }
        }
        return set;
    }

}
